/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stream_flow_control.h"
#include "utils_log.h"

namespace El {
namespace StreamService {

StreamFlowControl::StreamFlowControl(const std::string &name, uint32_t maxVideoFrames, uint32_t maxAudioFrames)
    : name_(name), maxVideoFrames_(maxVideoFrames), maxAudioFrames_(maxAudioFrames), logInterval_(100)
{
}

StreamFlowControl::Decision StreamFlowControl::ShouldAcceptFrame(const Media::MediaFramePtr &frame)
{
    if (!frame) {
        return Decision::DROP;
    }

    uint32_t frameType = frame->GetFrameType();
    bool isVideo = frame->IsVideoFrame();

    if (!isVideo) {
        // 音频流控：检查缓存是否已满
        uint64_t buffered = audioPushedFrames_ - audioReleasedFrames_;
        if (buffered >= maxAudioFrames_) {
            audioDroppedFrames_++;
            if (audioDroppedFrames_ % logInterval_ == 0) {
                EL_WARN("[{}] Audio buffer full ({}>={}), dropped {} frames", name_, buffered, maxAudioFrames_,
                        audioDroppedFrames_);
            }
            return Decision::DROP;
        }
        return Decision::ACCEPT;
    }

    // 视频流控：GOP完整性保证
    uint64_t buffered = videoPushedFrames_ - videoReleasedFrames_;
    bool isIFrame = (frameType == MEDIA_FRAME_I);

    // 情况1：缓存已满，丢弃所有帧（包括I帧）
    if (buffered >= maxVideoFrames_) {
        videoDroppedFrames_++;
        if (videoDroppedFrames_ % logInterval_ == 0) {
            EL_WARN("[{}] Video buffer full ({}>={}), dropped {} frames (waiting for buffer drain)", name_, buffered,
                    maxVideoFrames_, videoDroppedFrames_);
        }
        return Decision::DROP;
    }

    // 情况2：缓存未满，但之前丢过帧，需要等待I帧才能恢复
    if (videoDroppedFrames_ > 0 && !isIFrame) {
        videoDroppedFrames_++;
        return Decision::DROP; // 继续丢弃P/B帧，等待I帧
    }

    // 情况3：遇到I帧或从未丢帧，正常接受
    if (isIFrame && videoDroppedFrames_ > 0) {
        EL_INFO("[{}] Video recovered after dropping {} frames, resuming from I-frame", name_, videoDroppedFrames_);
        videoDroppedFrames_ = 0; // 清零丢帧计数，恢复正常推送
    }

    return Decision::ACCEPT;
}

void StreamFlowControl::OnFramePushed(bool isVideo)
{
    if (isVideo) {
        videoPushedFrames_++;
    } else {
        audioPushedFrames_++;
    }
}

void StreamFlowControl::OnFrameReleased(bool isVideo)
{
    if (isVideo) {
        videoReleasedFrames_++;
    } else {
        audioReleasedFrames_++;
    }
}

StreamFlowControl::Statistics StreamFlowControl::GetStatistics() const
{
    Statistics stats;
    stats.videoPushedFrames = videoPushedFrames_;
    stats.videoReleasedFrames = videoReleasedFrames_;
    stats.videoBufferedFrames = videoPushedFrames_ - videoReleasedFrames_;
    stats.videoDroppedFrames = videoDroppedFrames_;

    stats.audioPushedFrames = audioPushedFrames_;
    stats.audioReleasedFrames = audioReleasedFrames_;
    stats.audioBufferedFrames = audioPushedFrames_ - audioReleasedFrames_;
    stats.audioDroppedFrames = audioDroppedFrames_;

    stats.videoWaitingIFrame = (videoDroppedFrames_ > 0);

    return stats;
}

void StreamFlowControl::Reset()
{
    videoPushedFrames_ = 0;
    videoReleasedFrames_ = 0;
    videoDroppedFrames_ = 0;

    audioPushedFrames_ = 0;
    audioReleasedFrames_ = 0;
    audioDroppedFrames_ = 0;
}

void StreamFlowControl::SetLogInterval(uint32_t interval)
{
    logInterval_ = interval;
}

} // namespace StreamService
} // namespace El
